package com.zlll.winner.service.activity;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zlll.winner.business.model.activity.ActivityApplyExternal;
import com.zlll.winner.business.model.activity.ActivityCity;
import com.zlll.winner.business.model.activity.ActivityManagement;
import com.zlll.winner.business.service.activity.IActivityApplyExternalService;
import com.zlll.winner.business.service.activity.IActivityCityService;
import com.zlll.winner.business.service.area.IAreaCityService;
import com.zlll.winner.business.vo.activity.ActivityListVo;
import com.zlll.winner.business.vo.activity.ActivityVo;
import com.zlll.winner.config.RabbitDelayConfig;
import com.zlll.winner.enums.CommonEnum;
import com.zlll.winner.enums.activity.ActivityEnum;
import com.zlll.winner.mapper.activity.ActivityManagementMapper;
import com.zlll.winner.business.service.activity.IActivityManagementService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author qsx
 * @since 2019-09-16
 */
@Service
@Slf4j
public class ActivityManagementServiceImpl extends ServiceImpl<ActivityManagementMapper, ActivityManagement> implements IActivityManagementService {

    @Autowired
    private ActivityManagementMapper managementMapper;
    @Autowired
    private IActivityCityService cityService;
    @Autowired
    private IActivityApplyExternalService externalService;
    @Autowired
    private IAreaCityService areaCityService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public IPage getActivityManagementPage(String title, String cityCode, Integer status, Long startTime, Long endTime, Integer pageNo, Integer pageSize) {
        IPage<ActivityVo> page = new Page<ActivityVo>(pageNo, pageSize);

        List<ActivityVo> list = managementMapper.getActivityByPage(title, cityCode, status, startTime, endTime, page);
        page.setRecords(list);
        return page;
    }

    @Override
    @Transactional
    public ActivityManagement add(ActivityManagement activityManagement, Long userId) {
        Long time = System.currentTimeMillis();
        activityManagement.setCreateTime(time);
        if (activityManagement.getCityName().equals("全国")) {
            activityManagement.setScope(1);
        } else {
            activityManagement.setScope(2);
        }
        activityManagement.setCreateUser(userId + "");
        managementMapper.insert(activityManagement);
        editCityAndApplyExternal(activityManagement, time, true, userId);
        return activityManagement;
    }

    public void editCityAndApplyExternal(ActivityManagement activityManagement, Long time, Boolean isAdd, Long userId) {
        AtomicReference<Boolean> exist = new AtomicReference<>(false);

        List<ActivityCity> cityList = new ArrayList<>();
        if (activityManagement.getCityList() != null && activityManagement.getCityList().size() > 0) {
            for (Map cityMapList : activityManagement.getCityList()) {
                ActivityCity city = new ActivityCity();

                city.setCityId(cityMapList.get("cityId") == null ? 0l : Long.parseLong(cityMapList.get("cityId").toString()));
                city.setCityName(cityMapList.get("cityName") == null ? "" : cityMapList.get("cityName").toString());
                city.setCityCode(cityMapList.get("cityCode") == null ? "" : cityMapList.get("cityCode").toString());
                city.setCreateTime(time);
                city.setActivityId(activityManagement.getId());
                city.setCreateUser(userId + "");
                cityList.add(city);
            }
        }

        if (!isAdd) {
            LambdaQueryWrapper<ActivityCity> cityLambdaQueryWrapper = Wrappers.lambdaQuery();
            cityLambdaQueryWrapper.eq(ActivityCity::getIsDel, 0);
            cityLambdaQueryWrapper.eq(ActivityCity::getActivityId, activityManagement.getId());
            List<ActivityCity> cities = cityService.list(cityLambdaQueryWrapper);
            for (ActivityCity oldCity : cities) {
                exist.set(true);
                for (ActivityCity newCity : cityList) {
                    if (oldCity.getCityCode().equals(newCity.getCityCode())) {
                        newCity.setId(oldCity.getId());
                        newCity.setUpdateTime(time);
                        newCity.setCreateTime(oldCity.getCreateTime());
                        newCity.setCreateUser(oldCity.getCreateUser());
                        exist.set(false);

                    }
                }
                if (exist.get()) {
                    oldCity.setIsDel(1);
                    oldCity.setUpdateTime(time);
                    cityList.add(oldCity);
                }
            }
        }
        if (cityList.size() > 0) {
            cityService.saveOrUpdateBatch(cityList);
        }
        List<ActivityApplyExternal> externalList = new ArrayList<>();
        if (activityManagement.getExternals() != null && activityManagement.getExternals().size() > 0) {
            System.out.println(JSON.toJSONString(activityManagement.getExternals()));
            externalList = JSONObject.parseArray(JSON.toJSONString(activityManagement.getExternals()), ActivityApplyExternal.class);
            int num = 1;
            for (ActivityApplyExternal external : externalList) {
                external.setCreateUser(userId + "");
                external.setCreateTime(time);
                external.setIsDel(0);
                external.setActivityId(activityManagement.getId());
                external.setCode("external" + num);
                num++;
            }
        }
        //编辑时删除
        if (!isAdd) {
            LambdaQueryWrapper<ActivityApplyExternal> externalLambdaQueryWrapper = Wrappers.lambdaQuery();
            externalLambdaQueryWrapper.eq(ActivityApplyExternal::getIsDel, 0);
            externalLambdaQueryWrapper.eq(ActivityApplyExternal::getActivityId, activityManagement.getId());
            List<ActivityApplyExternal> externals = externalService.list(externalLambdaQueryWrapper);

            for (ActivityApplyExternal oldExternal : externals) {
                exist.set(true);
                for (ActivityApplyExternal newExternal : externalList) {
                    if (newExternal.getId() != null && oldExternal.getId().equals(newExternal.getId())) {
                        exist.set(false);
                        newExternal.setCreateTime(oldExternal.getCreateTime());
                        newExternal.setUpdateTime(time);
                        newExternal.setCreateUser(oldExternal.getCreateUser());
                        break;
                    }
                }

                if (exist.get()) {
                    oldExternal.setIsDel(1);
                    oldExternal.setUpdateTime(time);
                    externalList.add(oldExternal);
                }
            }

        }
        if (externalList.size() > 0) {
            externalService.saveOrUpdateBatch(externalList);
        }

        ActivityManagement management = getById(activityManagement.getId());
        if (!management.getStatus().equals(0) && !management.getStatus().equals(6)) {
            Integer status = management.getStatus();
            formatStatus(management, time);
            //判断当前时间是否有状态变更有则变更数据
            if (!status.equals(management.getStatus())) {
                updateById(management);
            }
            //更新数据到数据库之后，判断是否是当天执行的
            Long day = getNowadaysTime(23, 59, 59, 999);

            //当天新增(当前时间<设定的时间<当天结束时间)的活动，发送至rabbitmq来当天按时更新状态
            if (management.getApplyStartTime() != null && management.getApplyStartTime() >= time && management.getApplyStartTime() <= day) {
                Long timeDelay = management.getApplyStartTime() - time;
                sendManagementToRabbitmq(management, timeDelay);
            }
            if (management.getApplyEndTime() != null && management.getApplyEndTime() >= time && management.getApplyEndTime() <= day) {
                Long timeDelay = management.getApplyEndTime() - time;
                sendManagementToRabbitmq(management, timeDelay);
            }
            if (management.getActivityStartTime() >= time && management.getActivityStartTime() <= day) {
                Long timeDelay = management.getActivityStartTime() - time;
                sendManagementToRabbitmq(management, timeDelay);
            }
            if (management.getActivityEndTime() >= time && management.getActivityEndTime() <= day) {
                Long timeDelay = management.getActivityEndTime() - time;
                sendManagementToRabbitmq(management, timeDelay);
            }

        }

    }

    @Override
    public ActivityManagement edit(ActivityManagement activityManagement, Long userId) {
        Long time = System.currentTimeMillis();
        activityManagement.setUpdateTime(time);
        if (activityManagement.getCityName().equals("全国")) {
            activityManagement.setScope(1);
        } else {
            activityManagement.setScope(2);
        }
        saveOrUpdate(activityManagement);

        editCityAndApplyExternal(activityManagement, time, false, userId);
        return activityManagement;
    }

    @Override
    public Boolean updateStatus(Long id, Integer status, Long userId) {
        ActivityManagement management = getById(id);
        Long time = System.currentTimeMillis();
        management.setStatus(status);
        management.setUpdateTime(time);
        management.setUpdateUser(userId + "");
        return updateById(management);
    }

    @Override
    @Transactional
    public Boolean deleteActivityById(Long id, Long userId) {
        ActivityManagement activityManagement = managementMapper.selectById(id);
        activityManagement.setIsDel(1);
        activityManagement.setUpdateTime(System.currentTimeMillis());
        activityManagement.setUpdateUser(userId + "");
        return updateById(activityManagement);
    }

    @Override
    public Map getActivityInfo(Long id) {
        ActivityManagement activityManagement = managementMapper.selectById(id);
        LambdaQueryWrapper<ActivityCity> cityLambdaQueryWrapper = Wrappers.lambdaQuery();
        cityLambdaQueryWrapper.eq(ActivityCity::getIsDel, 0);
        cityLambdaQueryWrapper.eq(ActivityCity::getActivityId, id);
        List<ActivityCity> cities = cityService.list(cityLambdaQueryWrapper);

        LambdaQueryWrapper<ActivityApplyExternal> externalLambdaQueryWrapper = Wrappers.lambdaQuery();
        externalLambdaQueryWrapper.eq(ActivityApplyExternal::getIsDel, 0);
        externalLambdaQueryWrapper.eq(ActivityApplyExternal::getActivityId, id);
        List<ActivityApplyExternal> externals = externalService.list(externalLambdaQueryWrapper);
        Map result = new HashMap();
        result.put("activityManagement", activityManagement);
        result.put("cities", cities);
        result.put("externals", externals);

        return result;
    }

    @Override
    public IPage<ActivityListVo> getHomePage(String cityName, Integer pageSize, Integer pageNo) {
        IPage<ActivityListVo> page = new Page<ActivityListVo>(pageNo, pageSize);

        String cityCode = null;
        if (cityName != null) {
            cityCode = areaCityService.getCityCode(cityName);
        }
        List<ActivityListVo> list = managementMapper.getActivityByCondition(cityCode, page);
        page.setRecords(list);
        return page;
    }

    @Override
    public Boolean isApply(Long id) {
        ActivityManagement management = managementMapper.selectById(id);
        if (management.getMaxPeopleNum() != null && management.getMaxPeopleNum().equals(management.getApplyNum())) {
            return false;
        }
        return true;
    }

    @Override
    public void updateStatus(Long id) {
        Long time = System.currentTimeMillis();
        ActivityManagement management = getById(id);
        if (management != null && !management.getStatus().equals(0) && !management.getStatus().equals(6)) {
            Integer status = management.getStatus();
            formatStatus(management, time);
            if (!status.equals(management.getStatus())) {
                updateById(management);
            }
        }
    }

    @Override
    public void todayUpdate() {
        Long day = getNowadaysTime(23, 59, 59, 999);
        // 获取报名开始时间小于当天结束时的活动
        List<ActivityManagement> abList = list(Wrappers.<ActivityManagement>lambdaQuery()
                .select(ActivityManagement::getId,
                        ActivityManagement::getStatus,
                        ActivityManagement::getTitle,
                        ActivityManagement::getApplyStartTime)
                .eq(ActivityManagement::getStatus, ActivityEnum.StatusEnum.NOTSTART.val())
                .eq(ActivityManagement::getIsDel, CommonEnum.DelEnum.UNDEL.val())
                .le(ActivityManagement::getApplyStartTime, day));
        for (ActivityManagement m : abList) {
            Long time = m.getApplyStartTime() - Calendar.getInstance().getTimeInMillis();
            sendManagementToRabbitmq(m,time);
        }
        // 获取报名结束时间在今天范围内的活动
        List<ActivityManagement> aeList = list(Wrappers.<ActivityManagement>lambdaQuery()
                .select(ActivityManagement::getId,
                        ActivityManagement::getStatus,
                        ActivityManagement::getTitle,
                        ActivityManagement::getApplyStartTime,
                        ActivityManagement::getApplyEndTime)
                .in(ActivityManagement::getStatus,  ActivityEnum.StatusEnum.NOTSTART.val(), ActivityEnum.StatusEnum.APPLY.val())
                .eq(ActivityManagement::getIsDel, CommonEnum.DelEnum.UNDEL.val())
                .le(ActivityManagement::getApplyEndTime, day));
        for (ActivityManagement m : aeList) {
            Long time = m.getApplyEndTime() - Calendar.getInstance().getTimeInMillis();
            sendManagementToRabbitmq(m,time);
        }
        // 获取活动开始时间在今天范围内的活动
        List<ActivityManagement> mbList = list(Wrappers.<ActivityManagement>lambdaQuery()
                .select(ActivityManagement::getId,
                        ActivityManagement::getStatus,
                        ActivityManagement::getTitle,
                        ActivityManagement::getActivityStartTime)
                .in(ActivityManagement::getStatus, ActivityEnum.StatusEnum.NOTSTART.val(), ActivityEnum.StatusEnum.APPLY.val(),
                        ActivityEnum.StatusEnum.WAITINGSTART.val())
                .eq(ActivityManagement::getIsDel, CommonEnum.DelEnum.UNDEL.val())
                .le(ActivityManagement::getActivityStartTime, day));
        for (ActivityManagement m : mbList) {
            Long time = m.getActivityStartTime() - Calendar.getInstance().getTimeInMillis();
            sendManagementToRabbitmq(m,time);
        }
        // 获取活动结束时间在今天范围内的活动
        List<ActivityManagement> meList = list(Wrappers.<ActivityManagement>lambdaQuery()
                .select(ActivityManagement::getId,
                        ActivityManagement::getStatus,
                        ActivityManagement::getTitle,
                        ActivityManagement::getActivityEndTime)
                .in(ActivityManagement::getStatus, ActivityEnum.StatusEnum.NOTSTART.val(), ActivityEnum.StatusEnum.APPLY.val(),
                        ActivityEnum.StatusEnum.WAITINGSTART.val(), ActivityEnum.StatusEnum.EVENT.val())
                .eq(ActivityManagement::getIsDel, CommonEnum.DelEnum.UNDEL.val())
                .le(ActivityManagement::getActivityEndTime, day));
        for (ActivityManagement m : meList) {
            Long time = m.getActivityEndTime() - Calendar.getInstance().getTimeInMillis();
            sendManagementToRabbitmq(m,time);
        }
    }


    public void formatStatus(ActivityManagement management, Long time) {
        if (!management.getActivityType().equals(1)) {
            //设置活动状态 报名类
            if (management.getApplyStartTime() > time) {
                management.setStatus(1);
            }
            //报名中级别最高  再和其他状态重复是 优先设置报名中状态
            if (management.getApplyStartTime() <= time && management.getApplyEndTime() > time) {
                management.setStatus(2);
                return;
            }
            if (management.getApplyEndTime() <= time && management.getActivityStartTime() > time) {
                management.setStatus(3);
            }
            if (management.getActivityStartTime() <= time && management.getActivityEndTime() >= time) {
                management.setStatus(4);
            }
            if (management.getActivityEndTime() < time) {
                management.setStatus(5);
            }
        } else {
            //设置活动状态 广告类
            if (management.getActivityStartTime() > time) {
                management.setStatus(3);
            }
            if (management.getActivityStartTime() <= time && management.getActivityEndTime() >= time) {
                management.setStatus(4);
            }
            if (management.getActivityEndTime() < time) {
                management.setStatus(5);
            }
        }
    }

    /**
     * 、
     * 获取当天毫秒数
     */
    private Long getNowadaysTime(int hour, int minute, int second, int mil) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, mil);
        return calendar.getTimeInMillis();
    }

    /**
     * 发送活动状态到rabbitmq
     */
    private void sendManagementToRabbitmq(ActivityManagement management, Long time) {
        Integer t = time > 0 ? time.intValue() : 0;
        log.info("活动状态延时刷新,当前的活动是：id={},主题={},延时时间={}", management.getId(), management.getTitle(), time);
        //第一个参数是前面RabbitMqConfig的交换机名称 第二个参数的路由名称 第三个参数是传递的参数 第四个参数是配置属性
        this.rabbitTemplate.convertAndSend(
                RabbitDelayConfig.ACTIVE_DELAY_EXCHANGE,
                RabbitDelayConfig.ACTIVE_DELAY_ROUTING_KEY,
                management,
                message -> {
                    // 指定延迟时间(单位是毫秒)
                    message.getMessageProperties().setDelay(t);
                    return message;
                });
    }


}
